unit Sound;

interface

uses
  sysutils,
  FMod,
  FModErrors,
  FMODTypes,
  Debug,
  PakFile,
  Head;

Type

  TSoundType = (Music, Effect, Wav);

  TSoundData = record
    SoundID: integer;
    datalen: integer;
    data: array of byte;
  end;

  PSoundData = ^TSounddata;

const

  MaxSoundEffect = 100;
  MaxSoundWave  = 256;
  DISTANCEFACTOR = 1;

type

  Tsound = class
    Soundsustained: boolean;
    FMODSystem: FMOD_SYSTEM;
    FMODSound: FMOD_Sound;
    FMODChannel_Music: FMOD_Channel;
    FMODResult: FMOD_Result;
    FMODVersion: Cardinal;
    FModMusicData: TSoundData;
    FMODEffect: array[0..MaxSoundEffect - 1] of FMOD_Channel;
    FMODEffectSound: array[0..MaxSoundEffect - 1] of FMOD_Sound;
    FMODEffectData: array[0..MaxSoundEffect - 1] of TsoundData;
    FModWave: array[0..MaxSoundWave - 1] of FMOD_Channel;
    FMODWaveSound: array[0..MaxSoundWave - 1] of FMOD_Sound;
    FModWaveData: array[0..MaxSoundWave - 1] of TSoundData;
    NowWaveChannel: integer;
    Pak: TPakFile;
    MusicVolume: Single;
    EffectVolume: Single;
    WaveVolume: Single;
    nowMusicVolume: Single;
    nowEffectVolume: Single;
    nowWaveVolume: Single;
    DefaultMusicVolume,
    DefaultWaveVolume,
    DefaultEffectVolume: Single;
    destructor Destroy;
    function Initial: integer;
    procedure Release;
    procedure PlayMusic; overload;
    procedure PlayMusic(Name: String); overload;
    procedure PlayMusic(Data: Pbyte; datalen: integer); overload;
    procedure PlayMusicEx(x, y, z: Single); overload;
    procedure PlayMusicEx(Name: String; x, y, z: Single); overload;
    procedure PlayMusicEx(Data: Pbyte; datalen: integer; x, y, z: single); overload;
    procedure PlayWave(Num: integer); overload;
    procedure PlayWave(Name: String); overload;
    procedure PlayWave(Data: Pbyte; datalen: integer); overload;
    procedure PlayWaveEx(Num: integer; x, y, z: single); overload;
    procedure PlayWaveEx(Name: String; x, y, z: single); overload;
    procedure PlayWaveEx(Data: Pbyte; datalen: integer; x, y, z: single); overload;
    procedure PlayEffect(Num: integer); overload;
    procedure PlayEffect(Data: Pbyte; datalen, Num: integer); overload;
    procedure PlayEffectEx(Num: integer; x, y, z: single); overload;
    procedure PlayEffectEx(Data: Pbyte; datalen, Num: integer; x, y, z: single); overload;
    procedure SetMusic3D(x, y, z: single);
    procedure SetWave3D(Num: integer; x, y, z: single);
    procedure SetEffect3D(Num: integer; x, y, z: single);
    procedure StopMusic;
    procedure StopEffect(Num: integer);
    procedure StopWave(Num: integer);
    procedure StopAllEffect;
    procedure StopAllWave;
    procedure StopAllSound;
    procedure update;
    function LoadSoundFromBuffer(PData: Pbyte; BufLen, SoundID: integer; SoundType: TSoundType; num: integer): integer;
    function LoadSoundFromPak(PakName, SoundName: string; SoundType: TSoundType; num: integer): integer;
    function LoadSoundFromFile(SoundName: string; SoundType: TSoundType; num: integer): integer;
    function copypakbuftosounddata(PakF: PPakfile; Sounddata: Psounddata): integer;
    procedure SetEffectVolume(Volume: Single);
    procedure SetMusicVolume(Volume: Single);
    procedure SetWaveVolume(Volume: Single);
    procedure Restore;
    procedure Silent;
  end;

  Psound = ^TSound;

implementation

destructor Tsound.Destroy;
begin
  Release;
  inherited Destroy;
end;

function Tsound.Initial: integer;
var
  n: integer;
begin
  //
  GameDebug.AddDebugInfo('Create FMOD System!');
  if FMOD_SYSTEM_CREATE(FMODSystem) <> FMOD_OK then
  begin
    GameDebug.AddDebugInfo('Create FMOD System Fail!');
    result := 2;
    exit;
  end;

  GameDebug.AddDebugInfo('Get FMOD Version!');
  if FMOD_System_GetVersion(FMODsystem, FMODVersion) <> FMOD_OK then
  begin
    GameDebug.AddDebugInfo('Create FMOD System Fail!');
    result := 3;
    exit;
  end;

  if FMODVersion < FMOD_Version then
  begin
    GameDebug.AddDebugInfo('An Old Version FMOD!');
    result := 4;
    exit;
  end;

  GameDebug.AddDebugInfo('FMOD System Initial!');
  if FMOD_System_Init(FMODSystem, MaxSoundWave + MaxSoundEffect + 1, FMOD_INIT_NORMAL, nil) <> FMOD_OK then
  begin
    GameDebug.AddDebugInfo('FMOD System Initial Fail!');
    result := 5;
    exit;
  end;

  GameDebug.AddDebugInfo('FMOD 3D Setting!');
  if FMOD_System_Set3DSettings(Fmodsystem, 1.0, DISTANCEFACTOR, 1.0) <> FMOD_OK then
  begin
    GameDebug.AddDebugInfo('FMOD 3D Setting Fail!');
    result := 6;
    exit;
  end;

  Pak := TPakFIle.Create;

  NowWaveChannel := 0;

  Soundsustained := false;

  DefaultWaveVolume := 1;
  DefaultMusicVolume := 1;
  DefaultEffectVolume := 1;

  WaveVolume := DefaultWaveVolume;
  MusicVolume := DefaultMusicVolume;
  EffectVolume := DefaultEffectVolume;
  nowWaveVolume := DefaultWaveVolume;
  nowMusicVolume := DefaultMusicVolume;
  nowEffectVolume := DefaultEffectVolume;

  result := 0;
end;

procedure TSound.SetMusicVolume(Volume: Single);
begin
  FMOD_Channel_SetVolume(FMODChannel_Music, Volume);
end;

procedure TSound.SetWaveVolume(Volume: Single);
var
  I: integer;
begin
  for I := 0 to MaxSoundWave - 1 do
    if FMODWave[I] <> nil then
      FMOD_Channel_SetVolume(FMODWave[I], Volume);
end;

procedure TSound.SetEffectVolume(Volume: Single);
var
  I: integer;
begin
  for I := 0 to MaxSoundEffect - 1 do
    if FMODEffect[I] <> nil then
      FMOD_Channel_SetVolume(FMODEffect[I], Volume);
end;

procedure TSound.Restore;
begin
  nowMusicVolume := MusicVolume;
  nowEffectVolume := EffectVolume;
  nowWaveVolume := WaveVolume;
  SetMusicVolume(nowMusicVolume);
  SetEffectVolume(nowEffectVolume);
  SetWaveVolume(nowWaveVolume);
end;

procedure TSound.Silent;
begin
  nowMusicVolume := 0;
  nowEffectVolume := 0;
  nowWaveVolume := 0;
  SetMusicVolume(nowMusicVolume);
  SetEffectVolume(nowEffectVolume);
  SetWaveVolume(nowWaveVolume);
end;

function TSound.LoadSoundFromBuffer(PData: Pbyte; BufLen, SoundID: integer; SoundType: TSoundType; num: integer): integer;
begin
  case SoundType of
    Music:
      begin
        FMODMusicData.datalen := Buflen;
        FMODMusicData.SoundID := SoundID;
        setlength(FMODMusicData.data, FMODMusicData.datalen);
        move(Pdata^, FMODMusicData.data[0], FMODMusicData.datalen);
      end;
    Effect:
      begin
        if (num < 0) or (num >= MaxSoundEffect) then
        begin
          result := 1;
          exit;
        end;
        FMODEffectData[num].datalen := Buflen;
        FMODEffectData[num].SoundID := SoundID;
        setlength(FMODEffectData[num].data, FMODEffectData[num].datalen);
        move(Pdata^, FMODEffectData[num].data[0], FMODEffectData[num].datalen);
      end;
    Wav:
      begin
        if (num < 0) or (num >= MaxSoundWave) then
        begin
          result := 1;
          exit;
        end;
        FMODWaveData[num].datalen := Buflen;
        FMODWaveData[num].SoundID := SoundID;
        setlength(FMODWaveData[num].data, FMODWaveData[num].datalen);
        move(Pdata^, FMODWaveData[num].data[0], FMODWaveData[num].datalen);
      end;
  end;
  result := 0;
end;

function TSound.LoadSoundFromPak(PakName, SoundName: string; SoundType: TSoundType; num: integer): integer;
begin
  result := 1;
  if Pak.ReadFromFileToBuffer(PakName, SoundName) <> 0 then
  begin
    exit;
  end;
  result := LoadSoundFromBuffer(@Pak.databuffer[0], Pak.bufferlen, Pak.HashUnicodeFileName(SoundName), SoundType, num);
  Pak.ClearBuffer;
end;

function TSound.LoadSoundFromFile(SoundName: string; SoundType: TSoundType; num: integer): integer;
var
  len, FH: integer;
  data: array of byte;
begin
  //
  if not Fileexists(SoundName) then
  begin
    result := 1;
    exit;
  end;
  FH := FileOpen(SoundName, fmopenread);
  len := fileseek(FH, 0, 2);
  fileseek(FH, 0, 0);
  setlength(data, len);
  fileread(FH, data[0], len);
  Fileclose(FH);
  result := LoadSoundFromBuffer(@data[0], len, Pak.HashUnicodeFileName(SoundName), SoundType, num);
  setlength(data, 0);
end;

function TSound.copypakbuftosounddata(PakF: PPakfile; Sounddata: Psounddata): integer;
begin
  result := PakF.bufferlen;
  if PakF.bufferlen > 0 then
  begin
    Sounddata.datalen := PakF.bufferlen;
    setlength(Sounddata.data, Sounddata.datalen);
    Move(PakF.databuffer[0], Sounddata.data[0], Sounddata.datalen);
  end;
end;

procedure TSound.playMusic;
begin
  if FMODMusicData.datalen > 0 then
    playMusic(@FMODMusicData.data[0], FMODMusicData.datalen);
end;

procedure TSound.playMusic(Name: String);
begin
  GameDebug.AddDebugInfo('Play Music File:' + Name + '!');
  FMOD_Channel_Stop(FMODChannel_Music);
  FMOD_Sound_Release(Fmodsound);
  FMOD_System_CreateStream(FMODSystem, Pchar(StrtoAnsi(Name)), FMOD_HARDWARE or FMOD_LOOP_NORMAL or FMOD_2D, 0, FMODSound);
  FMOD_System_PlaySound(FMODsystem, FMOD_CHANNEL_FREE, Fmodsound, false, FMODchannel_Music);
end;

procedure TSound.PlayMusic(Data: Pbyte; datalen: integer);
var
  exinfo: FMOD_CREATESOUNDEXINFO;
begin
  GameDebug.AddDebugInfo('Play Music From Buffer!');
  FMOD_Channel_Stop(FMODChannel_Music);
  FMOD_Sound_Release(Fmodsound);
  fillchar(exinfo, sizeof(FMOD_CREATESOUNDEXINFO), 0);
  exinfo.cbsize := sizeof(FMOD_CREATESOUNDEXINFO);
  exinfo.length := datalen;
  if FMOD_System_CreateStream(FMODSystem, Pchar(data), FMOD_OPENMEMORY or FMOD_HARDWARE or FMOD_LOOP_NORMAL or FMOD_2D, @exinfo, FMODSound) <> FMOD_OK then
  begin
    GameDebug.AddDebugInfo('Create Sound From Buffer Fail!');
    exit;
  end;
  if FMOD_System_PlaySound(FMODsystem, FMOD_CHANNEL_FREE, Fmodsound, false, FMODchannel_Music) <> FMOD_OK then
  begin
    GameDebug.AddDebugInfo('Play Sound From Buffer Fail!');
    exit;
  end;

end;

procedure TSound.playMusicEx(x, y, z: Single);
begin
  if FMODMusicData.datalen > 0 then
    playMusicEx(@FMODMusicData.data[0], FMODMusicData.datalen, x, y, z);
end;

procedure TSound.playMusicEx(Name: String; x, y, z: single);
var
  pos, vel: FMOD_VECTOR;
begin
  GameDebug.AddDebugInfo('Play Music File:' + Name + '!');
  FMOD_Channel_Stop(FMODChannel_Music);
  FMOD_Sound_Release(Fmodsound);
  FMOD_System_CreateStream(FMODSystem, Pchar(StrtoAnsi(Name)), FMOD_HARDWARE or FMOD_LOOP_NORMAL or FMOD_3D, 0, FMODSound);
  FMOD_Sound_Set3DMinMaxDistance(FMODChannel_Music, -10000 * DISTANCEFACTOR, 10000 * DISTANCEFACTOR);
  FMOD_System_PlaySound(FMODsystem, FMOD_CHANNEL_FREE, Fmodsound, true, FMODchannel_Music);
  pos.x := x;
  pos.y := y;
  pos.z := z;
  vel.x := 0;
  vel.y := 0;
  vel.z := 0;
  FMOD_Channel_Set3DAttributes(FMODchannel_Music, pos, vel);

  FMOD_Channel_SetPaused(FMODChannel_Music, false);

end;

procedure TSound.PlayMusicEx(Data: Pbyte; datalen: integer; x, y, z: single);
var
  exinfo: FMOD_CREATESOUNDEXINFO;
  pos, vel: FMOD_VECTOR;
begin
  GameDebug.AddDebugInfo('Play Music From Buffer!');
  FMOD_Channel_Stop(FMODChannel_Music);
  FMOD_Sound_Release(Fmodsound);
  Fillchar(exinfo, sizeof(FMOD_CREATESOUNDEXINFO), 0);
  exinfo.cbsize := sizeof(FMOD_CREATESOUNDEXINFO);
  exinfo.length := datalen;
  if FMOD_System_CreateStream(FMODSystem, Pchar(data), FMOD_OPENMEMORY or FMOD_HARDWARE or FMOD_LOOP_NORMAL or FMOD_3D, @exinfo, FMODSound) <> FMOD_OK then
  begin
    GameDebug.AddDebugInfo('Create Sound From Buffer Fail!');
    exit;
  end;
  FMOD_Sound_Set3DMinMaxDistance(FMODChannel_Music, -10000 * DISTANCEFACTOR, 10000 * DISTANCEFACTOR);
  if FMOD_System_PlaySound(FMODsystem, FMOD_CHANNEL_FREE, Fmodsound, true, FMODchannel_Music) <> FMOD_OK then
  begin
    GameDebug.AddDebugInfo('Play Sound From Buffer Fail!');
    exit;
  end;
  pos.x := x;
  pos.y := y;
  pos.z := z;
  vel.x := 0;
  vel.y := 0;
  vel.z := 0;
  FMOD_Channel_Set3DAttributes(FMODchannel_Music, pos, vel);

  FMOD_Channel_SetPaused(FMODChannel_Music, false);

end;

procedure TSound.PlayWave(Num: integer);
begin
  if (Num >= 0) and (Num <= MaxSoundWave - 1 ) then
    if FMODWaveData[Num].datalen > 0 then
      playWave(@FmodWaveData[Num].data[0], FmodWaveData[Num].datalen);
end;

procedure TSound.playWave(Name: String);
begin
  GameDebug.AddDebugInfo('Play Music File:' + Name + '!');
  FMOD_Channel_Stop(FMODWave[NowWaveChannel]);
  FMOD_Sound_Release(FMODWaveSound[NowWaveChannel]);
  FMOD_System_CreateSound(FMODSystem, Pchar(StrtoAnsi(Name)), FMOD_HARDWARE or FMOD_LOOP_OFF or FMOD_2D, nil, FMODWaveSound[NowWaveChannel]);
  FMOD_System_PlaySound(FMODsystem, FMOD_CHANNEL_FREE, FMODWaveSound[NowWaveChannel], false, FMODWave[NowWaveChannel]);
  inc(NowWaveChannel);
  if NowWaveChannel > MaxSoundWave - 1 then
    NowWaveChannel := 0;
end;

procedure TSound.PlayWave(Data: Pbyte; datalen: integer);
var
  exinfo: FMOD_CREATESOUNDEXINFO;
begin
  FMOD_Channel_Stop(FMODWave[NowWaveChannel]);
  FMOD_Sound_Release(FMODWaveSound[NowWaveChannel]);
  Fillchar(exinfo, sizeof(FMOD_CREATESOUNDEXINFO), 0);
  exinfo.cbsize := sizeof(FMOD_CREATESOUNDEXINFO);
  exinfo.length := datalen;
  if FMOD_System_CreateSound(FMODSystem, Pchar(data), FMOD_OPENMEMORY or FMOD_HARDWARE or FMOD_LOOP_OFF or FMOD_2D, @exinfo, FMODWaveSound[NowWaveChannel]) <> FMOD_OK then
  begin
    exit;
  end;
  if FMOD_System_PlaySound(FMODsystem, FMOD_CHANNEL_FREE, FMODWaveSound[NowWaveChannel], false, FMODWave[NowWaveChannel]) <> FMOD_OK then
  begin
    exit;
  end;

  inc(NowWaveChannel);
  if NowWaveChannel > MaxSoundWave - 1 then
    NowWaveChannel := 0;
end;

procedure TSound.PlayWaveEx(Num: integer; x, y, z: single);
begin
  if (Num >= 0) and (Num <= MaxSoundWave - 1 ) then
    if FMODWaveData[Num].datalen > 0 then
      if (x = 0) and (y = 0) and (z = 0) then
        playWave(@FmodWaveData[Num].data[0], FmodWaveData[Num].datalen)
      else
        playWaveEx(@FmodWaveData[Num].data[0], FmodWaveData[Num].datalen, x, y, z);
end;

procedure TSound.playWaveEx(Name: String; x, y, z: single);
var
  pos, vel: FMOD_VECTOR;
begin
  GameDebug.AddDebugInfo('Play Music File:' + Name + '!');
  FMOD_Channel_Stop(FMODWave[NowWaveChannel]);
  FMOD_Sound_Release(FMODWaveSound[NowWaveChannel]);
  FMOD_System_CreateSound(FMODSystem, Pchar(StrtoAnsi(Name)), FMOD_3D or FMOD_HARDWARE or FMOD_LOOP_OFF, nil, FMODWaveSound[NowWaveChannel]);
  FMOD_System_PlaySound(FMODsystem, FMOD_CHANNEL_FREE, FMODWaveSound[NowWaveChannel], true, FMODWave[NowWaveChannel]);

  pos.x := x;
  pos.y := y;
  pos.z := z;
  vel.x := 0;
  vel.y := 0;
  vel.z := 0;
  FMOD_Channel_Set3DAttributes(FMODWave[NowWaveChannel], pos, vel);
  FMOD_Channel_SetPaused(FMODWave[NowWaveChannel], false);

  inc(NowWaveChannel);
  if NowWaveChannel > MaxSoundWave - 1 then
    NowWaveChannel := 0;
end;

procedure TSound.PlayWaveEx(Data: Pbyte; datalen: integer; x, y, z: single);
var
  exinfo: FMOD_CREATESOUNDEXINFO;
  pos, vel: FMOD_VECTOR;
begin

  FMOD_Channel_Stop(FMODWave[NowWaveChannel]);
  FMOD_Sound_Release(FMODWaveSound[NowWaveChannel]);
  Fillchar(exinfo, sizeof(FMOD_CREATESOUNDEXINFO), 0);
  exinfo.cbsize := sizeof(FMOD_CREATESOUNDEXINFO);
  exinfo.length := datalen;
  if FMOD_System_CreateSound(FMODSystem, Pchar(data), FMOD_3D or FMOD_OPENMEMORY or FMOD_HARDWARE or FMOD_LOOP_OFF, @exinfo, FMODWaveSound[NowWaveChannel]) <> FMOD_OK then
  begin
    GameDebug.AddDebugInfo('Create Sound From Buffer Fail!');
    exit;
  end;
  if FMOD_System_PlaySound(FMODsystem, FMOD_CHANNEL_FREE, FMODWaveSound[NowWaveChannel], true, FMODWave[NowWaveChannel]) <> FMOD_OK then
  begin
    GameDebug.AddDebugInfo('Play Sound From Buffer Fail!');
    exit;
  end;

  pos.x := x;
  pos.y := y;
  pos.z := z;
  vel.x := 0;
  vel.y := 0;
  vel.z := 0;
  FMOD_Channel_Set3DAttributes(FMODWave[NowWaveChannel], pos, vel);
  FMOD_Channel_SetPaused(FMODWave[NowWaveChannel], false);

  inc(NowWaveChannel);
  if NowWaveChannel > MaxSoundWave - 1 then
    NowWaveChannel := 0;
end;

procedure TSound.PlayEffect(Num: integer);
begin
  if (Num >= 0) and (Num <= MaxSoundEffect - 1 ) then
    if FMODEffectData[Num].datalen > 0 then
      playWave(@FmodEffectData[Num].data[0], FmodEffectData[Num].datalen);
end;

procedure TSound.PlayEffect(Data: Pbyte; datalen, Num: integer);
var
  exinfo: FMOD_CREATESOUNDEXINFO;
begin
  FMOD_Channel_Stop(FMODEffect[Num]);
  FMOD_Sound_Release(FMODEffectSound[Num]);
  Fillchar(exinfo, sizeof(FMOD_CREATESOUNDEXINFO), 0);
  exinfo.cbsize := sizeof(FMOD_CREATESOUNDEXINFO);
  exinfo.length := datalen;
  if FMOD_System_CreateSound(FMODSystem, Pchar(data), FMOD_OPENMEMORY or FMOD_HARDWARE or FMOD_LOOP_NORMAL or FMOD_2D, @exinfo, FMODEffectSound[Num]) <> FMOD_OK then
  begin
    exit;
  end;
  if FMOD_System_PlaySound(FMODsystem, FMOD_CHANNEL_FREE, FMODEffectSound[Num], false, FMODEffect[Num]) <> FMOD_OK then
  begin
    exit;
  end;

end;

procedure TSound.PlayEffectEx(Num: integer; x, y, z: single);
begin
  if (Num >= 0) and (Num <= MaxSoundEffect - 1 ) then
    if FMODEffectData[Num].datalen > 0 then
      if (x = 0) and (y = 0) and (z = 0) then
        playWave(@FmodEffectData[Num].data[0], FmodEffectData[Num].datalen)
      else
        playWaveEx(@FmodEffectData[Num].data[0], FmodEffectData[Num].datalen, x, y, z);
end;

procedure TSound.PlayEffectEx(Data: Pbyte; datalen, Num: integer; x, y, z: single);
var
  exinfo: FMOD_CREATESOUNDEXINFO;
  pos, vel: FMOD_VECTOR;
begin

  FMOD_Channel_Stop(FMODEffect[Num]);
  FMOD_Sound_Release(FMODEffectSound[Num]);
  Fillchar(exinfo, sizeof(FMOD_CREATESOUNDEXINFO), 0);
  exinfo.cbsize := sizeof(FMOD_CREATESOUNDEXINFO);
  exinfo.length := datalen;
  if FMOD_System_CreateSound(FMODSystem, Pchar(data), FMOD_3D or FMOD_OPENMEMORY or FMOD_HARDWARE or FMOD_LOOP_NORMAL or FMOD_2D, @exinfo, FMODEffectSound[Num]) <> FMOD_OK then
  begin
    GameDebug.AddDebugInfo('Create Sound From Buffer Fail!');
    exit;
  end;
  if FMOD_System_PlaySound(FMODsystem, FMOD_CHANNEL_FREE, FMODEffectSound[Num], true, FMODEffect[Num]) <> FMOD_OK then
  begin
    GameDebug.AddDebugInfo('Play Sound From Buffer Fail!');
    exit;
  end;

  pos.x := x;
  pos.y := y;
  pos.z := z;
  vel.x := 0;
  vel.y := 0;
  vel.z := 0;
  FMOD_Channel_Set3DAttributes(FMODEffect[Num], pos, vel);
  FMOD_Channel_SetPaused(FMODEffect[Num], false);

end;

procedure Tsound.SetMusic3D(x, y, z: single);
var
  pos, vel: FMOD_VECTOR;
begin
  //
  pos.x := x;
  pos.y := y;
  pos.z := z;
  vel.x := 0;
  vel.y := 0;
  vel.z := 0;
  FMOD_Channel_Set3DAttributes(FMODSound, pos, vel);
end;

procedure Tsound.SetWave3D(Num: integer; x, y, z: single);
var
  pos, vel: FMOD_VECTOR;
begin
  //
  if (num < 0) or (num > MaxSoundWave - 1) then
    exit;
  pos.x := x;
  pos.y := y;
  pos.z := z;
  vel.x := 0;
  vel.y := 0;
  vel.z := 0;
  FMOD_Channel_Set3DAttributes(FMODWave[Num], pos, vel);
end;

procedure Tsound.SetEffect3D(Num: integer; x, y, z: single);
var
  pos, vel: FMOD_VECTOR;
begin
  //
  if (num < 0) or (num > MaxSoundEffect - 1) then
    exit;
  pos.x := x;
  pos.y := y;
  pos.z := z;
  vel.x := 0;
  vel.y := 0;
  vel.z := 0;
  FMOD_Channel_Set3DAttributes(FMODWave[Num], pos, vel);
end;

procedure Tsound.StopMusic;
begin
  FMOD_Channel_Stop(FMODChannel_Music);
end;

procedure Tsound.StopWave(Num: integer);
begin
  FMOD_Channel_Stop(FMODWave[Num]);
end;

procedure Tsound.StopEffect(Num: integer);
begin
    FMOD_Channel_Stop(FMODEffect[Num]);
end;

procedure Tsound.StopAllEffect;
var
  I: integer;
begin
  for I := 0 to MaxSoundEffect - 1 do
    FMOD_Channel_Stop(FMODEffect[I]);
end;

procedure Tsound.StopAllWave;
var
  I: integer;
begin
  for I := 0 to MaxSoundWave - 1 do
    FMOD_Channel_Stop(FMODWave[I]);
end;

procedure Tsound.update;
begin
  FMOD_System_Update(FMODSystem);
end;

procedure TSound.StopAllSound;
begin
  StopMusic;
  StopAllEffect;
  StopAllWave;
end;

procedure TSound.Release;
begin
  GameDebug.AddDebugInfo('Release FMOD!');
  StopAllSound;
  FMOD_Sound_Release(FMODSound);
  FMOD_System_Close(FMODSystem);
  FMOD_System_Release(FMODSystem);
  Pak.Free;
end;

end.
